home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue40 / Threads / HVSyncObjs.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-11-03  |  9.6 KB  |  401 lines

  1. unit HVSyncObjs;
  2. //
  3. // Written by Hallvard Vassbotn, hallvard@falcon.no
  4. //
  5. // Based on source code Copyright (c) 1998 by Reuters Group PLC
  6. // Reproduction and/or distribution of source code or DCUs strictly prohibited.
  7. //
  8. // For publication in The Delphi Magazine only
  9. //
  10. interface
  11.  
  12. uses
  13.   Windows,
  14.   SysUtils,
  15.   Classes
  16.   ;
  17.  
  18. type
  19.   TSynchroObject = class(TObject)
  20.   public
  21.     constructor Create; virtual;
  22.     procedure Acquire; virtual; abstract;
  23.     procedure Release; virtual; abstract;
  24.   end;
  25.   TSynchroObjectClass = class of TSynchroObject;
  26.  
  27.   TCriticalSection = class(TSynchroObject)
  28.   protected
  29.     FSection: TRTLCriticalSection;
  30.   public
  31.     constructor Create; override;
  32.     destructor Destroy; override;
  33.     procedure Acquire; override;
  34.     procedure Release; override;
  35.     procedure Enter;
  36.     procedure Leave;
  37.   end;
  38.  
  39.   TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError, wrMessage);
  40.   TWaitResults = set of TWaitResult;
  41.   THandleObject = class(TSynchroObject)
  42.   protected
  43.     FHandle: THandle;
  44.     FLastError: DWORD;
  45.   public
  46.     destructor Destroy; override;
  47.     procedure Acquire; override;
  48.     function WaitFor(Timeout: DWORD): TWaitResult;
  49.     property LastError: DWORD read FLastError;
  50.     property Handle: THandle read FHandle;
  51.   end;
  52.  
  53.   TWin32OpenNamedObjFunc = function (dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: PChar): THandle; stdcall;
  54.   TNamedObject = class(THandleObject)
  55.   protected
  56.     FOpenFunc : TWin32OpenNamedObjFunc;
  57.     procedure Initialize; virtual;
  58.   public
  59.     constructor Create; override;
  60.     constructor CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string); virtual;
  61.     constructor CreateSimple;
  62.     constructor CreateNamed(const Name: string);
  63.     constructor Open(DesiredAccess: DWORD; InheritHandle: boolean; const Name: string);
  64.     constructor OpenSimple(const Name: string);
  65.   end;
  66.   TNamedObjectClass = class of TNamedObject;
  67.  
  68.   TMutex = class(TNamedObject)
  69.   public
  70.     constructor CreateInit(SecurityAttributes: PSecurityAttributes; InitialOwner: boolean; const Name: string);
  71.     constructor CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string); override;
  72.     procedure Release; override;
  73.   end;
  74.  
  75.   TEvent = class(TNamedObject)
  76.   public
  77.     constructor CreateInit(SecurityAttributes: PSecurityAttributes; ManualReset, InitialState: Boolean; const Name: string);
  78.     constructor CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string); override;
  79.     constructor CreateAutoReset;
  80.     procedure SetEvent;
  81.     procedure ResetEvent;
  82.     procedure Acquire; override;
  83.     procedure Release; override;
  84.   end;
  85.  
  86.   TSemaphore = class(TNamedObject)
  87.   protected
  88.     procedure ReleaseSemaphore(ReleaseCount: longint; PreviousCount: PLongint);
  89.   public
  90.     constructor CreateInit(SecurityAttributes: PSecurityAttributes; InitialCount, MaximumCount: Longint; const Name: string);
  91.     constructor CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string); override;
  92.     procedure Release; override;
  93.     procedure ReleaseBy(Value: integer);
  94.     function  GetReleaseBy(Value: integer): longint;
  95.   end;
  96.  
  97.   TWaitableThreadList = class(TSemaphore)
  98.   private
  99.     FList: TThreadList;
  100.   protected
  101.     procedure Initialize; override;
  102.     procedure FreeItems;
  103.   public
  104.     destructor Destroy; override;
  105.     procedure Add(Item: TObject);
  106.     function Last: TObject;
  107.     function Count: integer;
  108.     property List: TThreadList read FList;
  109.   end;
  110.  
  111. function Win32Handle(Handle: THandle): THandle;
  112.  
  113. implementation
  114.  
  115. function Win32Handle(Handle: THandle): THandle;
  116. begin
  117.   if Handle = 0 then SysUtils.RaiseLastWin32Error;
  118.   Result := Handle;
  119. end;
  120.  
  121. { TSynchroObject }
  122.  
  123. constructor TSynchroObject.Create;
  124. begin
  125.   inherited Create;
  126. end;
  127.  
  128. { TCriticalSection }
  129.  
  130. constructor TCriticalSection.Create;
  131. begin
  132.   inherited Create;
  133.   InitializeCriticalSection(FSection);
  134. end;
  135.  
  136. destructor TCriticalSection.Destroy;
  137. begin
  138.   DeleteCriticalSection(FSection);
  139.   inherited Destroy;
  140. end;
  141.  
  142. procedure TCriticalSection.Acquire;
  143. begin
  144.   Enter;
  145. end;
  146.  
  147. procedure TCriticalSection.Release;
  148. begin
  149.   Leave;
  150. end;
  151.  
  152. procedure TCriticalSection.Enter;
  153. begin
  154.   EnterCriticalSection(FSection);
  155. end;
  156.  
  157. procedure TCriticalSection.Leave;
  158. begin
  159.   LeaveCriticalSection(FSection);
  160. end;
  161.  
  162. { THandleObject }
  163.  
  164. destructor THandleObject.Destroy;
  165. begin
  166.   if FHandle <> 0 then
  167.     CloseHandle(FHandle);
  168.   inherited Destroy;
  169. end;
  170.  
  171. function THandleObject.WaitFor(Timeout: DWORD): TWaitResult;
  172. begin
  173.   case WaitForSingleObject(Handle, Timeout) of
  174.     WAIT_ABANDONED: Result := wrAbandoned;
  175.     WAIT_OBJECT_0 : Result := wrSignaled;
  176.     WAIT_TIMEOUT  : Result := wrTimeout;
  177.     WAIT_FAILED   :
  178.       begin
  179.         Result := wrError;
  180.         FLastError := GetLastError;
  181.       end;
  182.   else
  183.     Result := wrError;
  184.   end;
  185. end;
  186.  
  187. procedure THandleObject.Acquire;
  188. // We define acquiring a waitable object the same as waiting for it to signal
  189. // Raise an exception if something went wrong
  190. begin
  191.   if WaitFor(INFINITE) <> wrSignaled then
  192.     RaiseLastWin32Error;
  193. end;
  194.  
  195. { TNamedObject }
  196.  
  197. constructor TNamedObject.Create;
  198. begin
  199.   inherited Create;
  200.   CreateSimple;
  201. end;
  202.  
  203. constructor TNamedObject.CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string);
  204. begin
  205.   Initialize;
  206. end;
  207.  
  208. constructor TNamedObject.CreateSimple;
  209. begin
  210.   CreateDefault(nil, '');
  211. end;
  212.  
  213. constructor TNamedObject.CreateNamed(const Name: string);
  214. begin
  215.   CreateDefault(nil, Name);
  216. end;
  217.  
  218. constructor TNamedObject.Open(DesiredAccess: DWORD; InheritHandle: boolean;  const Name: string);
  219. begin
  220. //  inherited Create;
  221.   Assert(Assigned(FOpenFunc));
  222.   FHandle := Win32Handle(FOpenFunc(DesiredAccess, InheritHandle, PChar(Name)));
  223.   Initialize;
  224. end;
  225.  
  226. constructor TNamedObject.OpenSimple(const Name: string);
  227. begin
  228.   Open(MUTEX_ALL_ACCESS, false, Name);
  229. end;
  230.  
  231. procedure TNamedObject.Initialize;
  232. begin
  233.   // Nothing to do here
  234. end;
  235.  
  236. { TMutex }
  237.  
  238. constructor TMutex.CreateInit(SecurityAttributes: PSecurityAttributes; InitialOwner: boolean; const Name: string);
  239. begin
  240.   FHandle := Win32Handle(Windows.CreateMutex(SecurityAttributes, InitialOwner, Pointer(Name)));
  241.   Initialize;
  242. end;
  243.  
  244. constructor TMutex.CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string);
  245. begin
  246.   CreateInit(SecurityAttributes, false, Name);
  247. end;
  248.  
  249. procedure TMutex.Release;
  250. begin
  251.   Windows.ReleaseMutex(Handle);
  252. end;
  253.  
  254. { TEvent }
  255.  
  256. constructor TEvent.CreateInit(SecurityAttributes: PSecurityAttributes; ManualReset,
  257.   InitialState: Boolean; const Name: string);
  258. begin
  259.   FOpenFunc := Windows.OpenEvent;
  260.   FHandle := Win32Handle(CreateEvent(SecurityAttributes, ManualReset, InitialState, Pointer(Name)));
  261.   Initialize;
  262. end;
  263.  
  264. constructor TEvent.CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string);
  265. begin
  266.   CreateInit(SecurityAttributes, True, False, Name);
  267. end;
  268.  
  269. constructor TEvent.CreateAutoReset;
  270. begin
  271.   CreateInit(nil, False, False, '');
  272. end;
  273.  
  274. procedure TEvent.SetEvent;
  275. begin
  276.   Windows.SetEvent(Handle);
  277. end;
  278.  
  279. procedure TEvent.ResetEvent;
  280. begin
  281.   Windows.ResetEvent(Handle);
  282. end;
  283.  
  284. procedure TEvent.Acquire;
  285. begin
  286.   SetEvent;
  287. end;
  288.  
  289. procedure TEvent.Release;
  290. begin
  291.   ResetEvent;
  292. end;
  293.  
  294. { TSemaphore }
  295.  
  296. constructor TSemaphore.CreateInit(SecurityAttributes: PSecurityAttributes; InitialCount, MaximumCount: Longint; const Name: string);
  297. begin
  298.   FHandle := Win32Handle(Windows.CreateSemaphore(SecurityAttributes, InitialCount, MaximumCount, Pointer(Name)));
  299.   Initialize;
  300. end;
  301.  
  302. constructor TSemaphore.CreateDefault(SecurityAttributes: PSecurityAttributes; const Name: string);
  303. begin
  304.   CreateInit(SecurityAttributes, 0, High(Longint), Name);
  305. end;
  306.  
  307. procedure TSemaphore.ReleaseSemaphore(ReleaseCount: longint; PreviousCount: PLongint);
  308. begin
  309.   Windows.ReleaseSemaphore(Handle, ReleaseCount, PreviousCount);
  310. end;
  311.  
  312. procedure TSemaphore.Release;
  313. begin
  314.   ReleaseSemaphore(1, nil);
  315. end;
  316.  
  317. procedure TSemaphore.ReleaseBy(Value: integer);
  318. begin
  319.   ReleaseSemaphore(Value, nil);
  320. end;
  321.  
  322. function TSemaphore.GetReleaseBy(Value: integer): longint;
  323. begin
  324.   ReleaseSemaphore(Value, @Result);
  325. end;
  326.  
  327. { TWaitableThreadList }
  328.  
  329. procedure TWaitableThreadList.Initialize;
  330. // To allow the user to select any of the existing constructors,
  331. // we do our specific initialization here
  332. begin
  333.   inherited Initialize;
  334.   FList := TThreadList.Create;
  335. end;
  336.  
  337. destructor TWaitableThreadList.Destroy;
  338. begin
  339.   FreeItems;
  340.   FList.Free;
  341.   FList := nil;
  342.   inherited Destroy;
  343. end;
  344.  
  345. procedure TWaitableThreadList.FreeItems;
  346. var
  347.   i : integer;
  348. begin
  349.   with FList.LockList do
  350.     try
  351.       for i := 0 to Count-1 do
  352.         TObject(List^[i]).Free;
  353.       Clear;
  354.     finally
  355.       FList.UnlockList;
  356.     end;
  357. end;
  358.  
  359. procedure TWaitableThreadList.Add(Item: TObject);
  360. // Add item in the beginning of the list
  361. begin
  362.   with FList.LockList do
  363.     try
  364.       Insert(0, Item);
  365.       Release;  // Signal that there is one more item in the list
  366.     finally
  367.       FList.UnlockList;
  368.     end;
  369. end;
  370.  
  371. function TWaitableThreadList.Last: TObject;
  372. // Remove the last item in the list
  373. // This should only be called after the list has been signalled, i.e. WaitFor has returned
  374. begin
  375.   with FList.LockList do
  376.     try
  377.       Assert(Count > 0);
  378.       if Count > 0 then
  379.       begin
  380.         Result := Items[Count-1];
  381.         Delete(Count-1);
  382.       end
  383.       else
  384.         Result := nil;
  385.     finally
  386.       FList.UnlockList;
  387.     end;
  388. end;
  389.  
  390. function TWaitableThreadList.Count: integer;
  391. begin
  392.   with FList.LockList do
  393.     try
  394.       Result := Count;
  395.     finally
  396.       FList.UnlockList;
  397.     end;
  398. end;
  399.  
  400. end.
  401.